/*
    a12_closure -

展示GClosure的使用.

*/
#include <glib.h>
#include <glib-object.h>


gint myfunc(gint num, const gchar* name, const gchar* hello)
{    
    g_print("%s, the %s\n", hello, name);
    g_print("num = %d, res= %d\n", num, num+1);
    return num+1;
}


static void g_cclosure_marshal_INT__INT_STRING(GClosure     *closure,
                                                GValue       *return_value,
                                                guint         n_param_values,
                                                const GValue *param_values,
                                                gpointer      invocation_hint,
                                                gpointer      marshal_data)
{
    typedef int (*Marshaller)(gint num, const gchar* name, const gchar* hello);
    Marshaller callback;
    GCClosure *cc = (GCClosure*) closure;
    gint ret, num;
    const gchar* name;
    const gchar* hello;

    g_assert(n_param_values == 2);
    g_assert(!G_CCLOSURE_SWAP_DATA (closure));      

    // gpointer data1, data2;
    // if (G_CCLOSURE_SWAP_DATA (closure))
    // {
    //     data1 = closure->data;
    //     data2 = g_value_peek_pointer(param_values + 0);
    // }
    // else
    // {
    //     data1 = g_value_peek_pointer (param_values + 0);
    //     data2 = closure->data;
    // }

    num = g_value_get_int(param_values + 0);
    name = g_value_get_string(param_values + 1);
    hello = closure->data;

    callback = (Marshaller) (marshal_data ? marshal_data : cc->callback);
    ret = callback(num, name, hello);
    g_value_set_int(return_value, ret);
}


static void test_closure(void)
{

    GValue ret = G_VALUE_INIT;
    GValue params[2]={G_VALUE_INIT,G_VALUE_INIT};
    GClosure *closure;

    closure = g_cclosure_new((GCallback) myfunc, "hello", NULL);
    g_closure_set_marshal(closure, g_cclosure_marshal_INT__INT_STRING);

    g_value_init(&params[0], G_TYPE_INT);
    g_value_set_int(&params[0], 1);
    g_value_init(&params[1], G_TYPE_STRING);
    g_value_set_string(&params[1], "world");
    g_value_init(&ret, G_TYPE_INT);
    g_value_set_int(&ret, 0);


    g_closure_invoke(closure, &ret, 2, params, NULL);

    g_assert(g_value_get_int(&ret) == 2);
    g_value_unset(&params[0]);
    g_value_unset(&params[1]);
    g_value_unset(&ret);

}

int main(int argc, char** argv)
{
    g_print("a12_closure start......\n");
    test_closure();
    return 0;
}